import pytest
from unittest.mock import MagicMock, patch
import requests


# 模拟API客户端（零网络调用）
class CvmClient:
    def __init__(self):
        self.responses = {
            # 基础响应
            "Success": {"Response": {"RequestId": "mock-req-123"}},

            # 参数验证错误
            "MissingParameter": {"Response": {"Error": {"Code": "MissingParameter"}}},
            "InvalidParameterValue.DiskSizeOutOfRange": {
                "Response": {"Error": {"Code": "InvalidParameterValue.DiskSizeOutOfRange"}}
            },
            "InvalidParameterValue.ClientTokenTooLong": {
                "Response": {"Error": {"Code": "InvalidParameterValue.ClientTokenTooLong"}}
            },
            "InvalidInstanceId.NotFound": {
                "Response": {"Error": {"Code": "InvalidInstanceId.NotFound"}}
            },
            "InvalidDiskId.NotFound": {
                "Response": {"Error": {"Code": "InvalidDiskId.NotFound"}}
            },

            # 资源状态错误
            "OperationDenied.DiskStatus": {
                "Response": {"Error": {"Code": "OperationDenied.DiskStatus"}}
            },

            # 权限与认证错误
            "AuthFailure": {"Response": {"Error": {"Code": "AuthFailure"}}},

            # 重复提交错误
            "ClientTokenConflict": {"Response": {"Error": {"Code": "ClientTokenConflict"}}}
        }

    def modify_disk(self, instance_id, disk_id, disk_size, client_token=None):
        # 模拟参数校验（严格按顺序检查）
        if not instance_id or not isinstance(instance_id, str):
            return self._build_response("InvalidInstanceId.NotFound")
        if not disk_id or not isinstance(disk_id, str):
            return self._build_response("InvalidDiskId.NotFound")

        # 参数范围校验
        if disk_size < 5 or disk_size > 32768:
            return self._build_response("InvalidParameterValue.DiskSizeOutOfRange")
        if client_token and len(client_token) > 64:
            return self._build_response("InvalidParameterValue.ClientTokenTooLong")

        # 模拟资源状态检查
        if disk_id in ["disk-in-use", "disk-attaching"]:
            return self._build_response("OperationDenied.DiskStatus")

        # 模拟权限检查
        if instance_id == "unauthorized-instance":
            return self._build_response("AuthFailure")

        # 模拟重复提交
        if client_token == "conflict-token":
            return self._build_response("ClientTokenConflict")

        # 默认成功响应
        return self._build_response("Success")

    def _build_response(self, code):
        """统一响应构建方法"""
        return self.responses.get(code, {"Response": {}})


# 测试用例
class TestModifyInstanceDisk:
    @pytest.fixture
    def client(self):
        return CvmClient()

    # 参数验证类错误
    @pytest.mark.parametrize("instance_id,disk_id,disk_size,client_token,expected_code", [
        (None, "disk-123", 50, None, "InvalidInstanceId.NotFound"),  # 缺少实例ID
        ("ins-123", None, 50, None, "InvalidDiskId.NotFound"),  # 缺少磁盘ID
        ("ins-123", "disk-123", 2, None, "InvalidParameterValue.DiskSizeOutOfRange"),  # 小于最小值
        ("ins-123", "disk-123", 32769, None, "InvalidParameterValue.DiskSizeOutOfRange"),  # 超过最大值
        ("ins-123", "disk-123", 50, "x" * 65, "InvalidParameterValue.ClientTokenTooLong")  # ClientToken过长
    ])
    def test_invalid_params(self, client, instance_id, disk_id, disk_size, client_token, expected_code):
        response = client.modify_disk(instance_id, disk_id, disk_size, client_token)
        assert response["Response"]["Error"]["Code"] == expected_code

    # 资源状态类错误
    @pytest.mark.parametrize("disk_id,expected_code", [
        ("disk-in-use", "OperationDenied.DiskStatus"),  # 磁盘正在使用
        ("disk-attaching", "OperationDenied.DiskStatus")  # 磁盘正在挂载
    ])
    def test_resource_status(self, client, disk_id, expected_code):
        response = client.modify_disk("ins-123", disk_id, 50)
        assert response["Response"]["Error"]["Code"] == expected_code

    # 权限与认证类错误
    @pytest.mark.parametrize("instance_id,expected_code", [
        ("unauthorized-instance", "AuthFailure"),  # 无权限实例
        ("ins-invalid", "InvalidInstanceId.NotFound")  # 无效实例ID
    ])
    def test_auth_errors(self, client, instance_id, expected_code):
        response = client.modify_disk(instance_id, "disk-123", 50)
        assert response["Response"]["Error"]["Code"] == expected_code

    # 重复提交类错误
    def test_client_token_conflict(self, client):
        response = client.modify_disk("ins-123", "disk-123", 50, "conflict-token")
        assert response["Response"]["Error"]["Code"] == "ClientTokenConflict"

    # 正常用例
    def test_success(self, client):
        response = client.modify_disk("ins-123", "disk-123", 50)
        assert response["Response"]["RequestId"] == "mock-req-123"
        assert "Error" not in response["Response"]


# 执行测试
if __name__ == "__main__":
    pytest.main(["-v", "--color=yes"])